package com.neusoft.neuiotms.dcam.fixed.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Maps;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.bizcore.web.utils.EasyPoiExcelUtil;
import com.neusoft.bizcore.web.utils.EasyPoiStylerColorImpl;
import com.neusoft.neuiotms.dcam.common.model.Location;
import com.neusoft.neuiotms.dcam.common.model.Manufacturer;
import com.neusoft.neuiotms.dcam.common.repository.LocationRepository;
import com.neusoft.neuiotms.dcam.common.repository.ManufacturerRepository;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.InventoryDutyConverter;
import com.neusoft.neuiotms.dcam.fixed.converter.InventoryResultConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryDutyDTO;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryDuty;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryPlan;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryResult;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryDutyStatus;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryPlanStatus;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ConnectionRelationRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryDutyRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryPlanRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryResultRepository;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryDutyService;
import com.neusoft.neuiotms.dcam.fixed.vo.InventoryResultVO;
import com.neusoft.neuiotms.micro.auth.AuthMicroService;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class InventoryDutyServiceImpl implements InventoryDutyService {

    @Autowired
    private InventoryDutyRepository inventoryDutyRepository;
    @Autowired
    private InventoryDutyConverter inventoryDutyConverter;
    @Autowired
    private InventoryPlanRepository inventoryPlanRepository;
    @Autowired
    private LocationRepository locationRepository;
    @Autowired
    private AssetTypeRepository assetTypeRepository;
    @Autowired
    private ConnectionRelationRepository relationRepository;
    @Autowired
    private InventoryResultConverter inventoryResultConverter;
    @Autowired
    private AuthMicroService authMicroService;
    //    @Autowired
    //    private DictionaryService dictionaryService;
    //    @Autowired
    //    private ManufacturerService manufacturerService;
    @Autowired
    private InventoryResultRepository inventoryResultRepository;
    @Autowired
    private ManufacturerRepository manufacturerRepository;

    @Override
    public List<InventoryDutyDTO> findAll(final Searchable searchable) {
        final List<InventoryDuty> models = this.inventoryDutyRepository.search(searchable);
        return this.inventoryDutyConverter.toListDTO(models);
    }

    @Override
    public Page<InventoryDutyDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<InventoryDuty> models = this.inventoryDutyRepository.search(pageable, searchable);
        return this.inventoryDutyConverter.toPageDTO(models);
    }

    @Override
    public InventoryDutyDTO create(final InventoryDutyDTO dto) {

        InventoryDuty model = this.inventoryDutyConverter.toModel(dto);

        InventoryPlan planModel = null;
        try {
            planModel = this.inventoryPlanRepository.getOne(dto.getInventoryPlanId());
            model.setInventoryPlan(planModel);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {dto.getInventoryPlanId() });
        }

        if (planModel != null) {
            // 如果已经下发的计划不能新建任务
            if (!InventoryPlanStatus.created.equals(planModel.getStatus())) {
                throw new UnitedException("计划已经下发,不能新建任务!", new Object[] {});
            }
        }

        if (model.getOrgRelation().size() > 0) {
            // 保存实体
            this.relationRepository.saveAll(model.getOrgRelation());
        }

        model = this.inventoryDutyRepository.save(model);

        return this.inventoryDutyConverter.toDTO(model);
    }

    @Override
    public InventoryDutyDTO details(final Long id) {

        final InventoryDuty model;
        try {
            model = this.inventoryDutyRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        return this.inventoryDutyConverter.toDTO(model, false);
    }

    @Override
    public void delete(final Long id) {
        InventoryDuty model;
        try {
            model = this.inventoryDutyRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final InventoryPlan planModel = model.getInventoryPlan();

        if (planModel != null) {
            // 如果已经下发的计划不能删除任务
            if (!InventoryPlanStatus.created.equals(planModel.getStatus())) {
                throw new UnitedException("计划已经下发,不能删除任务!", new Object[] {});
            }
        }

        // 组织
        model.getOrgRelation().forEach(m -> {
            this.relationRepository.deleteById(m.getId());
        });
        model.getOrgRelation().clear();

        // 删除任务
        this.inventoryDutyRepository.deleteById(id);
    }

    @Override
    public InventoryDutyDTO update(final Long id, final InventoryDutyDTO dto) {

        InventoryDuty model;
        try {
            model = this.inventoryDutyRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final InventoryPlan planModel = model.getInventoryPlan();

        if (planModel != null) {
            // 如果已经下发的计划不能新建任务
            if (!InventoryPlanStatus.created.equals(planModel.getStatus())) {
                throw new UnitedException("计划已经下发,不能修改任务!", new Object[] {});
            }
        }

        dto.setId(model.getId());
        model = this.inventoryDutyConverter.toModel(dto);

        model = this.inventoryDutyRepository.save(model);

        return this.inventoryDutyConverter.toDTO(model);
    }

    @Override
    public void enable(final Long id, final String status) {

        InventoryDuty model;
        try {
            model = this.inventoryDutyRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final InventoryPlan planModel = model.getInventoryPlan();

        if (planModel != null) {
            // 计划下发了才能确认任务
            if (!InventoryPlanStatus.issued.equals(planModel.getStatus())) {
                throw new UnitedException("只有下发的计划才能确认!", new Object[] {});
            }
        }

        if (status.equals("finish")) {
            model.setStatus(InventoryDutyStatus.finish);
        }

        if (status.equals("doing")) {
            model.setStatus(InventoryDutyStatus.doing);
        }

        this.inventoryDutyRepository.save(model);
    }

    @Override
    public Workbook download(final Long id) {

        InventoryDuty model;
        try {
            final Optional<InventoryDuty> opt = this.inventoryDutyRepository.findById(id); //getOne(id);
            model = opt.get();
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final List<InventoryResultVO> vos =
                new ArrayList<>();

        if ((model != null) && CollectionUtils.isNotEmpty(model.getDutyResults())) {
            model.setDutyResults(model.getDutyResults().subList(0, model.getDutyResults().size()));
        }

        model.getDutyResults().stream().map(m -> {
            return this.inventoryResultConverter.toVO(m);
        }).filter(ele -> null != ele).forEach(vos::add);

        final ExportParams param = new ExportParams("盘点资产明细", "资产详细", ExcelType.XSSF);
        param.setStyle(EasyPoiStylerColorImpl.class);
        final Workbook workbook = ExcelExportUtil.exportExcel(param, InventoryResultVO.class, vos);

        //资产类型候选
        //        final List<AssetType> allTypes = this.assetTypeRepository.findAll();
        //        final List<String> typeConstraint = new ArrayList<>();
        //        allTypes.stream().forEach(l -> {
        //            typeConstraint.add(l.getName() + DCAMConsts.DICTIONARY_SPLITOR + l.getCode());
        //        });

        //位置下拉候选框数据
        final List<Location> location = this.locationRepository.findAll();
        final List<String> locationConstraint = new ArrayList<>();
        location.stream().forEach(l -> {
            locationConstraint.add(l.getName() + DCAMConsts.DICTIONARY_SPLITOR + l.getCode());
        });

        // 人员下拉列表
        final ResultListDTO<Map<String, Object>> users = this.authMicroService.userIndex(Maps.newHashMap());
        final List<String> userConstraint =
                users.getData().stream().map(e -> e.get("name").toString()).collect(Collectors.toList());

        // 部门下拉列表
        final ResultListDTO<Map<String, Object>> orgs = this.authMicroService.orgIndex();
        final List<String> orgConstraint =
                orgs.getData().stream().map(e -> e.get("name").toString()).collect(Collectors.toList());

        // 状态
        //        final Searchable searchable = new Searchable();
        //        searchable.put("type", "inventoryResultStatus");
        //        final List<DictionaryDTO> resultStatus = this.dictionaryService.findAll(searchable);
        //        final List<String> statusConstraint = resultStatus.stream().map(m -> m.getText()).collect(Collectors.toList());

        // 供应商下拉
        //        final List<ManufacturerDTO> manufacturers = this.manufacturerService.findAll();
        //        final List<String> manufacturerConstraint =
        //                manufacturers.stream().map(m -> m.getName() + DCAMConsts.DICTIONARY_SPLITOR + m.getId())
        //                        .collect(Collectors.toList());

        // 设置下拉列表
        final Iterator<Sheet> iterator = workbook.iterator();
        while (iterator.hasNext()) {

            final Sheet sheet = iterator.next();

            //位置列加下拉候选框
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 2, 2, locationConstraint);

            // 变更位置
            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 11, 11, locationConstraint);

            // 类型添加下拉列表
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 3, 3, typeConstraint);

            // 使用人
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 4, 4, userConstraint);
            // 变更人
            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 12, 12, userConstraint);

            // 使用部门
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 5, 5, orgConstraint);
            // 变更部门
            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 13, 13, orgConstraint);

            // 状态
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 14, 14, statusConstraint);

            // 供应商
            //            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, 2, 65535, 7, 7, manufacturerConstraint);

        }

        return workbook;
    }

    /**
     * 上传盘点信息
     */
    @Override
    public String upload(final MultipartFile file, final Long id) {
        final StringBuilder errorMsg = new StringBuilder();
        final ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        params.setNeedVerify(true);
        try {
            final ExcelImportResult<InventoryResultVO> result =
                    ExcelImportUtil.importExcelMore(file.getInputStream(), InventoryResultVO.class, params);
            if (result.isVerifyFail()) {
                final List<InventoryResultVO> failList = result.getFailList();
                failList.forEach(l -> {
                    errorMsg.append("第" + (l.getRowNum() + 1) + "行," + l.getErrorMsg() + "! \n");
                });

            }

            final List<InventoryResult> models = new ArrayList<>();
            final List<InventoryResultVO> saveList = result.getList();

            for (final InventoryResultVO inventory : saveList) {
                if (StringUtils.isNotEmpty(inventory.getCode())) {
                    InventoryResult oldModel = null;

                    final List<InventoryResult> oldModelList =
                            this.inventoryResultRepository.getByDutyIdAndCode(id, inventory.getCode());

                    if (CollectionUtils.isNotEmpty(oldModelList)) {
                        oldModel = oldModelList.get(0);
                    }

                    if (oldModel != null) {
                        this.updateInventoryResult(models, inventory, oldModel);
                    } else {
                        this.inventoryProfit(id, models, inventory);
                    }
                }
            }

            if (!models.isEmpty()) {
                this.inventoryResultRepository.saveAll(models);
            }

        } catch (final Exception e) {
            e.printStackTrace();
            InventoryDutyServiceImpl.log.error("上传失败", e);
            throw new UnitedException(e.getMessage(), new Object[] {});
        }

        return errorMsg.toString();
    }

    // 更新盘点信息
    private void updateInventoryResult(final List<InventoryResult> models, final InventoryResultVO inventory,
            final InventoryResult oldModel) {
        // 存在子更新，变更的位置、使用人、部门
        if (StringUtils.isNotEmpty(inventory.getUpdateLocationName())) {
            final Location location =
                    this.locationRepository.findByName(inventory.getUpdateLocationName());
            oldModel.setUpdateLocation(location);
        }

        if (StringUtils.isNotEmpty(inventory.getUpdateUserName())) {
            final UserBean userBean =
                    this.authMicroService.loadUserByUsername(inventory.getUpdateUserName()).getData();
            oldModel.setUpdateUserName(inventory.getUpdateUserName());
            if (userBean != null) {
                oldModel.setUpdateUserId(String.valueOf(userBean.getUserId()));
            }
        }

        if (StringUtils.isNotEmpty(inventory.getUpdateOrgName())) {
            final ResultListDTO<Map<String, Object>> orgs = this.authMicroService.orgIndex();
            final List<String> orgCode =
                    orgs.getData()
                            .stream()
                            .filter(e -> e.get("name").equals(inventory.getUpdateOrgName()))
                            .map(e -> e.get("code").toString())
                            .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(orgCode)) {
                oldModel.setUpdateOrgCode(orgCode.get(0));
                oldModel.setUpdateOrgName(inventory.getUpdateOrgName());
            }
        }

        oldModel.setDutyResultStatus(inventory.getResultStatus());

        models.add(oldModel);
    }

    // 添加盘盈
    private void inventoryProfit(final Long id, final List<InventoryResult> models,
            final InventoryResultVO inventory) {
        final InventoryDuty inventoryDuty = this.inventoryDutyRepository.getOne(id);
        final InventoryResult model = this.inventoryResultConverter.toModel(inventory);

        //类型
        if (!StringUtils.isEmpty(inventory.getAssetTypeName())) {
            try {
                final AssetType type =
                        this.assetTypeRepository.findByName(inventory.getAssetTypeName());
                model.setType(type);
            } catch (final EntityNotFoundException e) {
                throw new UnitedException("资产类型不存在", new Object[] {inventory.getAssetTypeName() });
            }
        }
        //位置
        if (!StringUtils.isEmpty(inventory.getLocationName())) {
            try {
                final Location location =
                        this.locationRepository.findByName(inventory.getLocationName());
                model.setLocation(location);
            } catch (final EntityNotFoundException e) {
                throw new UnitedException("资产类型不存在", new Object[] {inventory.getLocationName() });
            }
        }

        // 使用人
        if (!StringUtils.isEmpty(inventory.getUserName())) {
            final UserBean userBean =
                    this.authMicroService.loadUserByUsername(inventory.getUserName()).getData();
            model.setUserName(inventory.getUserName());
            if (userBean != null) {
                model.setUserId(String.valueOf(userBean.getUserId()));
            }
        }

        // 部门
        if (!StringUtils.isEmpty(inventory.getOrgName())) {
            final ResultListDTO<Map<String, Object>> orgs = this.authMicroService.orgIndex();
            final List<String> orgCode =
                    orgs.getData()
                            .stream()
                            .filter(e -> e.get("name").equals(inventory.getOrgName()))
                            .map(e -> e.get("id").toString())
                            .collect(Collectors.toList());
            model.setOrgName(inventory.getOrgName());
            if (CollectionUtils.isNotEmpty(orgCode)) {
                model.setOrgId(orgCode.get(0));
            }
        }

        // 供应商
        if (!StringUtils.isEmpty(inventory.getManufacturerName())) {
            final Manufacturer manufacturer =
                    this.manufacturerRepository.findByName(inventory.getManufacturerName());
            if (manufacturer != null) {
                model.setManufacturer(manufacturer);
            }
        }

        if (inventoryDuty != null) {
            model.setInventoryDuty(inventoryDuty);
            model.setDutyResultStatus(inventory.getResultStatus());
            models.add(model);
        }
    }

}
